﻿using AIVision.Inspect;
using AIVision.Model;
using AIVision.Model.EntityModels;
using AIVision.Model.InspectModels;
using HalconDotNet;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace XRVision.BaseCheckUnit
{
    public class BaseCheckUnitInstance : ICheckUnit
    {
        private string _resource_path;
        public string ResourcePath
        {
            get
            {
                return _resource_path;
            }
            set
            {
                lock (_procedure_path_lock)
                {
                    _procedure_path_initialized = false;
                }
                _resource_path = value;
            }
        }

        public List<DefectItemDto> defectItems;


        private EnumInspectType inspectType = EnumInspectType.Base;
        public EnumInspectType InspectType { get => inspectType; }
        private int okScore;
        private Lazy<HDevProgram> _Program;
        private Lazy<HDevProcedure> _GetInspectImage;
        private Lazy<HDevProcedure> _CheckDefect;
        private Lazy<HDevProcedure> _GetInspectArea;
        public void Init(string hcFilePath, string processFilePath, string modelFilePath, HTuple dlDevice, List<DefectItemDto> defectItems,int okScore)
        {
            throw new Exception("初始化失败，检查类型匹配错误！");
        }

        public void Init(string hcFilePath,List<DefectItemDto> defectItems, int okScore)
        {
            this.defectItems = defectItems;
            _resource_path = hcFilePath;
            this.okScore = okScore;
            _Program = new Lazy<HDevProgram>(() => new HDevProgram(_resource_path));
            _CheckDefect  = new Lazy<HDevProcedure>(() => new HDevProcedure(_Program.Value, "CheckDefect"));
            _GetInspectArea = new Lazy<HDevProcedure>(() => new HDevProcedure(_Program.Value, "GetInspectArea"));
            _GetInspectImage = new Lazy<HDevProcedure>(() => new HDevProcedure(_Program.Value, "GetInspectImage"));
        }

        public void Stop()
        {

        }
        public InspectResultModel ExUnitCheck(HObject image)
        {
            InspectResultModel result = new InspectResultModel();
            result.Defects = new Dictionary<string, HObject>();
            result.InspectType = EnumInspectType.Base.ToString();
            result.SourceImage = image;
            result.InspectImage = null;
            result.OKScore = okScore;

            //1、切图

            HObject inspectImage;
            try
            {
                GetInspectImage(image, out inspectImage);
            }
            catch (Exception ex)
            {
                inspectImage = null;
                return result;
            }
            if (inspectImage == null)
            {
                result.Defects.Add("未找到产品！", null);
                return result;
            }
            //2、检查
            HObject defectArea = null;
            HTuple defectNames = null;
            CheckDefect(inspectImage, out defectArea,out defectNames);
            result.InspectImage = inspectImage;
            //检查完后如果不存在缺陷，就直接返回结果
            if(defectNames.Length==0)
            {
                result.Score = okScore;
                return result;
            }
            //如果存在缺陷


            var st = defectNames[0];

            //3、获取区域
            HObject inspectArea = null;
            HTuple areaCount = null;
            try
            {
                GetInspectArea(inspectImage, out inspectArea);
                HOperatorSet.CountObj(inspectArea, out areaCount);
            }
            catch (Exception ex)
            {
                result.Defects.Add("未找到产品区域！", null);
                return result;
            }
           
           
            int areaCountI = areaCount.I;
            if (areaCountI == 0)
                return result;
            HObject selectArea = null;
            HObject selectDefect = null;
            //循环个区域
            for (int i = 1; i < areaCountI + 1; i++)
            {
                HOperatorSet.SelectObj(inspectArea, out selectArea, i);
                //循环CheckDefect返回的缺陷
                for (int j= 0; j < defectNames.Length; j++)
                {
                    //获取配置的缺陷项目
                    var checkItem = defectItems.FirstOrDefault(m => m.DefectCode == defectNames.SArr[j]);
                    if (checkItem == null)   //如果未配置该缺陷项目，该缺陷忽略
                        continue;
                    HOperatorSet.SelectObj(defectArea, out selectDefect, j+1); //获取缺陷区域对象，缺陷对象索引从1开始
                    HOperatorSet.Intersection(selectArea, selectDefect, out selectDefect);//用区域减获取当前区域内的缺陷区域

                    if (checkItem.MinArea > 0)
                        HOperatorSet.SelectShape(selectDefect, out selectDefect, "area", "and", checkItem.MinArea, 999999);
                    if (checkItem.MinHeight > 0)
                        HOperatorSet.SelectShape(selectDefect, out selectDefect, "height", "and", checkItem.MinHeight, 999999);
                    if (checkItem.MinWidth > 0)
                        HOperatorSet.SelectShape(selectDefect, out selectDefect, "width", "and", checkItem.MinWidth, 999999);
                    if (checkItem.MaxStructFactor > 0)
                        HOperatorSet.SelectShape(selectDefect, out selectDefect, "struct_factor", "and", 0, checkItem.MaxStructFactor);
                    HObject htemp;
                    HOperatorSet.GenEmptyRegion(out htemp);     //创建空区域，用于对比最后选择的区域是否为空区域
                    HTuple hTuple = null;
                    HOperatorSet.TestEqualRegion(htemp, selectDefect, out hTuple);
                    if (hTuple.Length > 0 && hTuple.I == 0)
                        result.Defects.Add(i.ToString() + ":" + checkItem.DefectName, selectDefect);
                }
            }

            if (result.Defects.Count > 0)
                result.Score = 0;
            else
                result.Score = okScore;

            return result;
        }

        public void CheckDefect(HObject inspectImage,out HObject defectArea,out HTuple defectNames)
        {
            //AddResourcePathToProcedurePath();
            using (HDevProcedureCall call = _CheckDefect.Value.CreateCall())
            {
                SetParameter(call, "inspectImage", inspectImage);
                call.Execute();
                defectArea = GetParameterHObject(call, "defectArea");
                defectNames = GetParameterHTuple(call, "defectNames");
            }
        }

        public void GetInspectArea(HObject InspectImage,out HObject InspectArea)
        {
            //AddResourcePathToProcedurePath();
            using (HDevProcedureCall call = _GetInspectArea.Value.CreateCall())
            {
                SetParameter(call, "InspectImage", InspectImage);
                call.Execute();
                InspectArea = GetParameterHObject(call, "InspectArea");
            }
        }

        public void GetInspectImage(HObject SourceImage,out HObject InspectImage)
        {
            //AddResourcePathToProcedurePath();
            using (HDevProcedureCall call = _GetInspectImage.Value.CreateCall())
            {
                SetParameter(call, "SourceImage", SourceImage);
                call.Execute();
                InspectImage = GetParameterHObject(call, "InspectImage");
            }
        }




        #region 公共方法
        private bool _procedure_path_initialized = false;
        private object _procedure_path_lock = new object();

        private HTuple GetParameterHTuple(HDevProcedureCall call, string name)
        {
            return call.GetOutputCtrlParamTuple(name);
        }

        private HObject GetParameterHObject(HDevProcedureCall call, string name)
        {
            return call.GetOutputIconicParamObject(name);
        }

        private HTupleVector GetParameterHTupleVector(HDevProcedureCall call, string name)
        {
            return call.GetOutputCtrlParamVector(name);
        }

        private HObjectVector GetParameterHObjectVector(HDevProcedureCall call, string name)
        {
            return call.GetOutputIconicParamVector(name);
        }

        private void SetParameter(HDevProcedureCall call, string name, HTuple tuple)
        {
            call.SetInputCtrlParamTuple(name, tuple);
        }

        private void SetParameter(HDevProcedureCall call, string name, HObject obj)
        {
            call.SetInputIconicParamObject(name, obj);
        }

        private void SetParameter(HDevProcedureCall call, string name, HTupleVector vector)
        {
            call.SetInputCtrlParamVector(name, vector);
        }

        private void SetParameter(HDevProcedureCall call, string name, HObjectVector vector)
        {
            call.SetInputIconicParamVector(name, vector);
        }

        private void AddResourcePathToProcedurePath()
        {
            lock (_procedure_path_lock)
            {
                if (!_procedure_path_initialized)
                {
                    new HDevEngine().AddProcedurePath(ResourcePath);
                    _procedure_path_initialized = true;
                }
            }
        }
        #endregion
    }
}
